﻿using System;
using System.Collections.Generic;
using SharpDX;

namespace BoatNGoat
{
    /// <summary>
    /// Sprite class represents all the animations that can be retrieved using a single sprite sheet.
    /// </summary>
    public class Sprite
    {
        //TODO: Don't think this origin will be necessary any more.
        public Vector2 Origin { get; set; }
        public readonly SpriteSheet SpriteSheet;
        private readonly Dictionary<string, SpriteAnimation> _animations = new Dictionary<string, SpriteAnimation>();
        
        public Sprite(SpriteSheet sheet)
        {
            SpriteSheet = sheet;
        }

        /// <summary>
        /// Get the drawing rectangle that is used to draw a particular animation frame.
        /// </summary>
        /// <param name="animationName"></param>
        /// <param name="frame"></param>
        /// <returns></returns>
        public DrawingRectangle GetDrawingRectangle(string animationName, int frame)
        {
            SpriteAnimationFrame animationFrame = GetAnimation(animationName).AnimationFrames[frame];
            int row = animationFrame.Row;
            int column = animationFrame.Column;
            return SpriteSheet.GetSourceRectangle(column, row);  
        }

        /// <summary>
        /// Create a new animation that can be performed with this sprite sheet.
        /// </summary>
        /// <param name="animationName">The key used to refer to this animation.</param>
        /// <param name="animation">The <see cref="SpriteAnimation"/> that the key refers to.</param>
        public void CreateAnimation(string animationName, SpriteAnimation animation)
        {
            _animations[animationName] = animation;
        }

        public SpriteAnimation GetAnimation(string animationName)
        {
            return _animations[animationName];
        }
    }

    /// <summary>
    /// Stores a single state for a sprite's animation.
    /// </summary>
    public class SpriteAnimationState
    {
        public string AnimationName { get; set; }
        public int CurrentFrame { get; set; }
        public int FrameCount { get; set; }

        private float _ticks;
        private float _ticksPerFrame;

        public SpriteAnimationState(string animationName, int currentFrame, int frameCount, float ticksPerFrame)
        {
            AnimationName = animationName;
            CurrentFrame = currentFrame;
            FrameCount = frameCount;
            _ticksPerFrame = ticksPerFrame;
            _ticks = 0;
        }

        /// <summary>
        /// Move the sprite's current animation forwards by a number of frames, and update its values.
        /// </summary>
        /// <param name="ticks">The number of "ticks" to move forwards by.</param>
        public void Forwards(float ticks)
        {
            _ticks += ticks;

            // If it's time to move onto the next frame, reduce the current tick count by the per-frame amount.
            if (_ticks >= _ticksPerFrame)
            {
                CurrentFrame++;
                _ticks -= _ticksPerFrame;
            }

            // Take the modulo to allow for wrap-around.
            // i.e. if we have 4 frames but want to move forwards by 10, move forwards by 2.
            CurrentFrame %= FrameCount;
        }

        /// <summary>
        /// Move the sprite's current animation backwards by a number of frames, and update its values.
        /// </summary>
        /// <param name="ticks">The number of "ticks" to move backwards by.</param>
        public void Backwards(float ticks)
        {
            _ticks -= ticks;

            // If it's time to move onto the next (previous) frame, reduce the current tick count by the per-frame amount.
            if (_ticks <= -_ticksPerFrame)
            {
                CurrentFrame--;
                _ticks -= _ticksPerFrame;
            }

            if (CurrentFrame < 0)
                CurrentFrame += FrameCount;
        }

        public void SetAnimation(string animationName, int currentFrame, int frameCount, float ticksPerFrame)
        {
            AnimationName = animationName;
            CurrentFrame = currentFrame;
            FrameCount = frameCount;
            _ticksPerFrame = ticksPerFrame;
            _ticks = 0;
        }
    }
}
